"""
hello = world,
hell1 = xxhhxhx,
hell2 = ddhehehhxhx,
hello3 = {
    w1 = 23,
    w2 = 23,
    w3 = 23
},
hell4 = [
    string1,
    string2,
    string2
],
hello5 = [ 
    bytes:ddddddddddd
]



= => " = "
, => ",\n"
{ => "{\n"
}, => "},\n"
} => "}\n"

[ => "[\n"
], => "],\n"
] => "]\n"


"""

from bcat.util.assert_or_raise import AssertOrRaise
from bcat.gtp.serde.error import ExpectTypeError, ValueEmptyError

from bcat.gtp.serde.escape import Escape
from bcat.gtp.serde.iserializer import ISerializer
from bcat.gtp.serde.writer import Writer

#TODO:
class PrettyPrinter(ISerializer):
    def __init__(self, writer):
        AssertOrRaise(writer).not_none()
        super().__init__(writer, 'gbk')
        self.__level = 0

    def serialize(self, v):
        AssertOrRaise(v).not_none("v must be buffer").is_type(dict)

        if len(v) != 0:
            result = 0
            is_writed_some = False
            prefix_len = 0

            for key, value in v.items():
                prefix_len = self.write_prefix()
                writed_bytes_count = self.serialize_pair(key, value)
                if writed_bytes_count > 0: 
                    result += prefix_len
                    result += writed_bytes_count
                    result += self.serialize_pair_separator()
                    if not is_writed_some :
                        is_writed_some = True
                else:
                    self.writer().discard_back(prefix_len)

            if is_writed_some :
                result -= self.writer().discard_back(1) # remove the last char:','
            else:
                pass

            self.__level -= 1
            return result
        else:
            raise ValueEmptyError("dict which is serialized to gtp is null")

    def serialize_pair(self, key, value):
        result = 0
        result += self.serialize_key(key)
        result += self.serialize_key_value_separator()

        writed_bytes_count = self.serialize_value(value)
        if writed_bytes_count > 0:
            result += writed_bytes_count
        else:
            self.writer().discard_back(result)
            result = 0

        return result


    def serialize_pair_separator(self):
        return self.writer().write_bytes(b',')

    def serialize_key(self, key):
        result = Escape.from_str(key, self.encoding()).escape()
        return self.writer().write_bytes(result)
    def serialize_key_value_separator(self):
        return self.writer().write_bytes(b' = ')
    def serialize_value(self, v):
        if v is None:
            return self.serialize_none()

        tp = type(v)
        if tp is str:
            return self.serialize_str(v)
        elif tp is int:
            return self.serialize_int(v)
        elif tp is float:
            return self.serialize_float(v)
        elif tp is dict:
            return self.serialize_map(v)
        elif tp in (list, tuple):
            return self.serialize_list(v)
        elif tp is bool:
            return self.serialize_bool(v)
        elif tp in (bytes, bytearray, memoryview):
            return self.serialize_bytes(v)
        else:
            raise TypeError("not support type tto serialize :{}".format(tp))
    
    def serialize_none(self):
        return 0
    def serialize_bool(self, v):
        return self.writer().write_bytes(b'1' if v else b'0')

    def serialize_str(self, v):
        result = Escape.from_str(v, self.encoding()).escape()
        return self.writer().write_bytes(result)
    def serialize_bytes(self, v):
        result = Escape.from_bytes(v).escape()
        return self.writer().write_bytes(result)

    def serialize_int(self, v):
        return self.writer().write_str(str(v), self.encoding())

    def serialize_float(self, v):
        return self.writer().write_str(str(v), self.encoding())

    def serialize_map_start(self):
        return self.writer().write_bytes(b'{')
    def serialize_map_end(self):
        return self.writer().write_bytes(b'}')
        
    def serialize_map(self, v):
        if type(v) is dict:
            result = 0
            if len(v) != 0:
                is_writed_some = False
                result += self.serialize_map_start()
                self.__level += 1

                prefix_len = 0
                for key, value in v.items():
                    prefix_len = self.write_prefix()
                    writed_bytes_count = self.serialize_pair(key, value)
                    if writed_bytes_count > 0:
                        result += prefix_len + writed_bytes_count
                        result += self.serialize_pair_separator()
                        if not is_writed_some :
                            is_writed_some = True
                    else:
                        self.writer().discard_back(prefix_len)

                if is_writed_some: 
                    result -= self.writer().discard_back(1) # discard_back pair sep:','

                    self.__level -= 1

                    result += self.write_prefix()
                    result += self.serialize_map_end()

                else:  # all values is-empty -> discard_back map-start:'{'
                    result -= self.writer().discard_back(1)
                    self.__level -= 1

            else:  # map is null, ignore
                pass
            return result
        else:
            raise ExpectTypeError.from_real_value(dict, v)

    def serialize_list_start(self):
        return self.writer().write_bytes(b'[')
    def serialize_list_end(self):
        return self.writer().write_bytes(b']')
    def serialize_list(self, v):
        if type(v) is list:
            result = 0
            if len(v) > 0:
                is_writed_some = False
                result += self.serialize_list_start()
                self.__level += 1

                prefix_len = 0
                for e in v: 
                    prefix_len = self.write_prefix()
                    writed_bytes_count = self.serialize_value(e)
                    if writed_bytes_count > 0:
                        result += prefix_len + writed_bytes_count
                        result += self.serialize_pair_separator()
                        if not is_writed_some:
                            is_writed_some = True
                    else:
                        self.writer().discard_back(prefix_len)

                if is_writed_some:
                    result -= self.writer().discard_back(1) #discard_back pair sep:','

                    self.__level -= 1
                    result += self.write_prefix()
                    result += self.serialize_list_end()

                else: # all value is-empty -> discard_back list-start: '['
                    result -= self.writer().discard_back(1)
                    self.__level -= 1


            else: # list is null, ignore
                pass
            return result
        else:
            raise ExpectTypeError.from_real_value(list, v)

    def write_prefix(self):
        return self.writer().write_bytes(b'\n') + self.writer().write_bytes(b'    ' * self.__level)

import unittest
from bcat.gtp.serde.ser.bytes_writer import BytesWriter
class  TestPrettyPrinter(unittest.TestCase):
    def test_main(self):
        writer = BytesWriter.default()
        pp = PrettyPrinter(writer)
        pp.serialize({
                "X00":"ssss", 
                "X01":None,
                "X02":12, 
                "X03":23.34,
                "X04":True,
                "X05":False,
                "X06":b'aaaa',
                "X07" : [
                    [1, 1, 1], 
                    [2, 2, 2], 
                    3,
                    None,
                    5,
                ],
                "X08" : {
                    "Y01" : "sssss",
                    "Y02" : False,
                    "Y03" : None,
                    "Y04" : True,
                    "Y05" : {
                        "Z01" : {
                            "K01" : "string"
                        },
                        "Z02" : "hehhh",
                        "Z03" : None,
                        "Z04" : [
                            "strin0",
                            "strin1",
                            "strin2",
                            "strin3",
                        ],
                    }
                }
        })
        print()
        print(writer.target().decode())

if __name__ == '__main__':
    unittest.main(verbosity=2)
